#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#pragma pack(push, 1)
typedef struct {
    unsigned short bfType;      // "BM"
    unsigned int bfSize;        // 文件大小
    unsigned short bfReserved1; // 保留
    unsigned short bfReserved2; // 保留
    unsigned int bfOffBits;     // 图像数据偏移量
} BITMAPFILEHEADER;

typedef struct {
    unsigned int biSize;         // 结构体大小
    int biWidth;                 // 图像宽度(像素)
    int biHeight;                // 图像高度(像素)
    unsigned short biPlanes;     // 必须为1
    unsigned short biBitCount;   // 每像素位数
    unsigned int biCompression;  // 压缩类型
    unsigned int biSizeImage;    // 图像数据大小
    int biXPelsPerMeter;         // 水平分辨率
    int biYPelsPerMeter;         // 垂直分辨率
    unsigned int biClrUsed;      // 使用的颜色数
    unsigned int biClrImportant; // 重要颜色数
} BITMAPINFOHEADER;

typedef struct {
    unsigned char rgbBlue;
    unsigned char rgbGreen;
    unsigned char rgbRed;
    unsigned char rgbReserved;
} RGBQUAD;
#pragma pack(pop)

typedef struct {
    int width;
    int height;
    unsigned char *data; // 存储图像像素数据，按BGR顺序排列
} BMPImage;

// 三次立方插值权重函数
double cubicWeight(double x) {
    double absX = fabs(x);
    if (absX <= 1) {
        return 1 - 2 * absX * absX + absX * absX * absX;
    } else if (absX < 2) {
        return 4 - 8 * absX + 5 * absX * absX - absX * absX * absX;
    }
    return 0;
}

// 三次立方插值缩放
BMPImage *bicubicScale(BMPImage *src, float scale) {
    int newWidth = (int)(src->width * scale / 100);
    int newHeight = (int)(src->height * scale / 100);
    int channels = 3; // 假设为24位BMP

    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = newWidth;
    dst->height = newHeight;
    int dstRowSize = ((newWidth * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * newHeight);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < newHeight; y++) {
        for (int x = 0; x < newWidth; x++) {
            double srcX = x * (src->width - 1) / (double)(newWidth - 1);
            double srcY = y * (src->height - 1) / (double)(newHeight - 1);

            int x0 = (int)floor(srcX) - 1;
            int y0 = (int)floor(srcY) - 1;
            double dx = srcX - floor(srcX);
            double dy = srcY - floor(srcY);

            double value[3] = {0, 0, 0};
            double weightSum[3] = {0, 0, 0};

            for (int m = 0; m < 4; m++) {
                for (int n = 0; n < 4; n++) {
                    int px = x0 + n;
                    int py = y0 + m;

                    // 边界检查
                    if (px < 0) px = 0;
                    if (py < 0) py = 0;
                    if (px >= src->width) px = src->width - 1;
                    if (py >= src->height) py = src->height - 1;

                    double wx = cubicWeight(n - 1 - dx);
                    double wy = cubicWeight(m - 1 - dy);
                    double w = wx * wy;

                    for (int c = 0; c < channels; c++) {
                        unsigned char pixel = src->data[py * srcRowSize + px * channels + c];
                        value[c] += pixel * w;
                        weightSum[c] += w;
                    }
                }
            }

            for (int c = 0; c < channels; c++) {
                if (weightSum[c] != 0) {
                    value[c] /= weightSum[c];
                }
                dst->data[y * dstRowSize + x * channels + c] = 
                    (unsigned char)(value[c] < 0 ? 0 : (value[c] > 255 ? 255 : value[c] + 0.5));
            }
        }
    }

    return dst;
}
// 读取BMP文件
BMPImage *readBMP(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        fprintf(stderr, "无法打开文件: %s\n", filename);
        return NULL;
    }

    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;

    // 读取文件头和信息头
    if (fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, file) != 1 ||
        fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, file) != 1) {
        fclose(file);
        fprintf(stderr, "读取BMP头信息失败\n");
        return NULL;
    }

    // 检查是否是BMP文件
    if (fileHeader.bfType != 0x4D42) {
        fclose(file);
        fprintf(stderr, "不是有效的BMP文件\n");
        return NULL;
    }

    // 只支持24位和32位BMP
    if (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32) {
        fclose(file);
        fprintf(stderr, "只支持24位和32位BMP图像\n");
        return NULL;
    }

    // 分配内存存储图像数据
    BMPImage *image = (BMPImage *)malloc(sizeof(BMPImage));
    if (!image) {
        fclose(file);
        fprintf(stderr, "内存分配失败\n");
        return NULL;
    }

    image->width = infoHeader.biWidth;
    image->height = infoHeader.biHeight;
    int channels = infoHeader.biBitCount / 8;
    int rowSize = ((image->width * channels + 3) / 4) * 4; // BMP每行字节数必须是4的倍数

    image->data = (unsigned char *)malloc(rowSize * image->height);
    if (!image->data) {
        fclose(file);
        free(image);
        fprintf(stderr, "内存分配失败\n");
        return NULL;
    }

    // 移动到像素数据开始位置
    fseek(file, fileHeader.bfOffBits, SEEK_SET);

    // 读取像素数据
    if (fread(image->data, 1, rowSize * image->height, file) != rowSize * image->height) {
        fclose(file);
        free(image->data);
        free(image);
        fprintf(stderr, "读取像素数据失败\n");
        return NULL;
    }

    fclose(file);
    return image;
}

// 写入BMP文件
int writeBMP(const char *filename, BMPImage *image, int channels) {
    FILE *file = fopen(filename, "wb");
    if (!file) {
        fprintf(stderr, "无法创建文件: %s\n", filename);
        return 0;
    }

    int rowSize = ((image->width * channels + 3) / 4) * 4; // 每行字节数必须是4的倍数
    int imageSize = rowSize * image->height;

    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;

    // 填充文件头
    fileHeader.bfType = 0x4D42; // "BM"
    fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + imageSize;
    fileHeader.bfReserved1 = 0;
    fileHeader.bfReserved2 = 0;
    fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    // 填充信息头
    infoHeader.biSize = sizeof(BITMAPINFOHEADER);
    infoHeader.biWidth = image->width;
    infoHeader.biHeight = image->height;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = channels * 8;
    infoHeader.biCompression = 0;
    infoHeader.biSizeImage = imageSize;
    infoHeader.biXPelsPerMeter = 0;
    infoHeader.biYPelsPerMeter = 0;
    infoHeader.biClrUsed = 0;
    infoHeader.biClrImportant = 0;

    // 写入文件头和信息头
    if (fwrite(&fileHeader, sizeof(BITMAPFILEHEADER), 1, file) != 1 ||
        fwrite(&infoHeader, sizeof(BITMAPINFOHEADER), 1, file) != 1) {
        fclose(file);
        fprintf(stderr, "写入BMP头信息失败\n");
        return 0;
    }

    // 写入像素数据
    if (fwrite(image->data, 1, imageSize, file) != imageSize) {
        fclose(file);
        fprintf(stderr, "写入像素数据失败\n");
        return 0;
    }

    fclose(file);
    return 1;
}

// 释放BMP图像内存
void freeBMP(BMPImage *image) {
    if (image) {
        if (image->data) {
            free(image->data);
        }
        free(image);
    }
}

// 最近邻插值缩放
BMPImage *nearestNeighborScale(BMPImage *src, float scale) {
    int newWidth = (int)(src->width * scale / 100);
    int newHeight = (int)(src->height * scale / 100);
    int channels = 3; // 假设为24位BMP

    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = newWidth;
    dst->height = newHeight;
    int dstRowSize = ((newWidth * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * newHeight);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < newHeight; y++) {
        for (int x = 0; x < newWidth; x++) {
            int srcX = (int)(x * 100.0 / scale);
            int srcY = (int)(y * 100.0 / scale);

            if (srcX >= src->width) srcX = src->width - 1;
            if (srcY >= src->height) srcY = src->height - 1;

            for (int c = 0; c < channels; c++) {
                dst->data[y * dstRowSize + x * channels + c] = 
                    src->data[srcY * srcRowSize + srcX * channels + c];
            }
        }
    }

    return dst;
}

// 双线性插值缩放
BMPImage *bilinearScale(BMPImage *src, float scale) {
    int newWidth = (int)(src->width * scale / 100);
    int newHeight = (int)(src->height * scale / 100);
    int channels = 3; // 假设为24位BMP

    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = newWidth;
    dst->height = newHeight;
    int dstRowSize = ((newWidth * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * newHeight);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < newHeight; y++) {
        for (int x = 0; x < newWidth; x++) {
            float srcX = x * (src->width - 1) / (float)(newWidth - 1);
            float srcY = y * (src->height - 1) / (float)(newHeight - 1);

            int x1 = (int)srcX;
            int y1 = (int)srcY;
            int x2 = x1 + 1;
            int y2 = y1 + 1;

            if (x2 >= src->width) x2 = src->width - 1;
            if (y2 >= src->height) y2 = src->height - 1;

            float dx = srcX - x1;
            float dy = srcY - y1;

            for (int c = 0; c < channels; c++) {
                unsigned char v1 = src->data[y1 * srcRowSize + x1 * channels + c];
                unsigned char v2 = src->data[y1 * srcRowSize + x2 * channels + c];
                unsigned char v3 = src->data[y2 * srcRowSize + x1 * channels + c];
                unsigned char v4 = src->data[y2 * srcRowSize + x2 * channels + c];

                float val = v1 * (1 - dx) * (1 - dy) +
                            v2 * dx * (1 - dy) +
                            v3 * (1 - dx) * dy +
                            v4 * dx * dy;

                dst->data[y * dstRowSize + x * channels + c] = (unsigned char)(val + 0.5);
            }
        }
    }

    return dst;
}

// 旋转图像90度
BMPImage *rotate90(BMPImage *src) {
    int channels = 3; // 假设为24位BMP
    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = src->height;
    dst->height = src->width;
    int dstRowSize = ((dst->width * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * dst->height);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < dst->height; y++) {
        for (int x = 0; x < dst->width; x++) {
            int srcX = dst->height - 1 - y;
            int srcY = x;

            for (int c = 0; c < channels; c++) {
                dst->data[y * dstRowSize + x * channels + c] = 
                    src->data[srcY * srcRowSize + srcX * channels + c];
            }
        }
    }

    return dst;
}

// 旋转图像180度
BMPImage *rotate180(BMPImage *src) {
    int channels = 3; // 假设为24位BMP
    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = src->width;
    dst->height = src->height;
    int dstRowSize = ((dst->width * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * dst->height);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < dst->height; y++) {
        for (int x = 0; x < dst->width; x++) {
            int srcX = src->width - 1 - x;
            int srcY = src->height - 1 - y;

            for (int c = 0; c < channels; c++) {
                dst->data[y * dstRowSize + x * channels + c] = 
                    src->data[srcY * srcRowSize + srcX * channels + c];
            }
        }
    }

    return dst;
}

// 旋转图像270度
BMPImage *rotate270(BMPImage *src) {
    int channels = 3; // 假设为24位BMP
    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = src->height;
    dst->height = src->width;
    int dstRowSize = ((dst->width * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * dst->height);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < dst->height; y++) {
        for (int x = 0; x < dst->width; x++) {
            int srcX = y;
            int srcY = dst->width - 1 - x;

            for (int c = 0; c < channels; c++) {
                dst->data[y * dstRowSize + x * channels + c] = 
                    src->data[srcY * srcRowSize + srcX * channels + c];
            }
        }
    }

    return dst;
}

// 水平镜像
BMPImage *mirrorHorizontal(BMPImage *src) {
    int channels = 3; // 假设为24位BMP
    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = src->width;
    dst->height = src->height;
    int dstRowSize = ((dst->width * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * dst->height);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < dst->height; y++) {
        for (int x = 0; x < dst->width; x++) {
            int srcX = src->width - 1 - x;
            int srcY = y;

            for (int c = 0; c < channels; c++) {
                dst->data[y * dstRowSize + x * channels + c] = 
                    src->data[srcY * srcRowSize + srcX * channels + c];
            }
        }
    }

    return dst;
}

// 垂直镜像
BMPImage *mirrorVertical(BMPImage *src) {
    int channels = 3; // 假设为24位BMP
    BMPImage *dst = (BMPImage *)malloc(sizeof(BMPImage));
    if (!dst) return NULL;

    dst->width = src->width;
    dst->height = src->height;
    int dstRowSize = ((dst->width * channels + 3) / 4) * 4;
    dst->data = (unsigned char *)malloc(dstRowSize * dst->height);
    if (!dst->data) {
        free(dst);
        return NULL;
    }

    int srcRowSize = ((src->width * channels + 3) / 4) * 4;

    for (int y = 0; y < dst->height; y++) {
        for (int x = 0; x < dst->width; x++) {
            int srcX = x;
            int srcY = src->height - 1 - y;

            for (int c = 0; c < channels; c++) {
                dst->data[y * dstRowSize + x * channels + c] = 
                    src->data[srcY * srcRowSize + srcX * channels + c];
            }
        }
    }

    return dst;
}

void printUsage() {
    printf("用法:\n");
    printf("  缩放: imgproc -z -m method some.bmp xxx somenew.bmp\n");
    printf("    -z: 执行缩放操作\n");
    printf("    -m: 指定算法(n:最近邻, l:双线性, c:三次立方)\n");
    printf("    xxx: 缩放比例(1-999)\n");
    printf("  旋转: imgproc -r some.bmp xxx somenew.bmp\n");
    printf("    -r: 执行旋转操作\n");
    printf("    xxx: 旋转角度(0,90,180,270)\n");
    printf("  镜像: imgproc -m some.bmp -v/-h somenew.bmp\n");
    printf("    -m: 执行镜像操作\n");
    printf("    -v: 垂直镜像\n");
    printf("    -h: 水平镜像\n");
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printUsage();
        return 1;
    }

    BMPImage *srcImage = NULL;
    BMPImage *dstImage = NULL;
    int result = 0;

    if (strcmp(argv[1], "-z") == 0 && argc == 7) {
        // 缩放操作
        char *method = argv[3];
        char *inputFile = argv[4];
        float scale = atof(argv[5]);
        char *outputFile = argv[6];

        if (scale < 1 || scale > 999) {
            fprintf(stderr, "缩放比例必须在1-999之间\n");
            return 1;
        }

        srcImage = readBMP(inputFile);
        if (!srcImage) return 1;

        if (strcmp(method, "n") == 0) {
            dstImage = nearestNeighborScale(srcImage, scale);
        } else if (strcmp(method, "l") == 0) {
            dstImage = bilinearScale(srcImage, scale);
        }
            else if (strcmp(method, "c") == 0) {
            dstImage = bicubicScale(srcImage, scale);
        } else {
            fprintf(stderr, "不支持的缩放算法\n");
            freeBMP(srcImage);
            return 1;
        }

        if (dstImage) {
            result = writeBMP(outputFile, dstImage, 3);
            freeBMP(dstImage);
        }
    } else if (strcmp(argv[1], "-r") == 0 && argc == 5) {
        // 旋转操作
        char *inputFile = argv[2];
        int angle = atoi(argv[3]);
        char *outputFile = argv[4];

        if (angle != 0 && angle != 90 && angle != 180 && angle != 270) {
            fprintf(stderr, "旋转角度必须是0,90,180或270\n");
            return 1;
        }

        srcImage = readBMP(inputFile);
        if (!srcImage) return 1;

        if (angle == 0) {
            dstImage = srcImage;
            srcImage = NULL; // 防止被释放
        } else if (angle == 90) {
            dstImage = rotate90(srcImage);
        } else if (angle == 180) {
            dstImage = rotate180(srcImage);
        } else if (angle == 270) {
            dstImage = rotate270(srcImage);
        }

        if (dstImage) {
            result = writeBMP(outputFile, dstImage, 3);
            freeBMP(dstImage);
        }
    } else if (strcmp(argv[1], "-m") == 0 && argc == 5) {
        // 镜像操作
        char *inputFile = argv[2];
        char *direction = argv[3];
        char *outputFile = argv[4];

        srcImage = readBMP(inputFile);
        if (!srcImage) return 1;

        if (strcmp(direction, "-h") == 0) {
            dstImage = mirrorHorizontal(srcImage);
        } else if (strcmp(direction, "-v") == 0) {
            dstImage = mirrorVertical(srcImage);
        } else {
            fprintf(stderr, "镜像方向必须是-h(水平)或-v(垂直)\n");
            freeBMP(srcImage);
            return 1;
        }

        if (dstImage) {
            result = writeBMP(outputFile, dstImage, 3);
            freeBMP(dstImage);
        }
    } else {
        printUsage();
        return 1;
    }

    freeBMP(srcImage);
    return result ? 0 : 1;
}